package cz.possoft.explorer;

import cz.possoft.explorer.context.ObjectContextBuilder;
import cz.possoft.explorer.converter.Converter;
import cz.possoft.explorer.converter.ConverterImpl;
import cz.possoft.explorer.converter.ConverterProvider;
import cz.possoft.explorer.converter.ConverterProviderImpl;
import cz.possoft.explorer.meta.DomainMetadata;
import cz.possoft.explorer.meta.builder.DomainMetadataBuilder;
import cz.possoft.explorer.meta.builder.XMLDomainMetadataBuilderImpl;

/**
 * Initialize instances of application components and contains registry of these components. 
 * 
 * TODO: use some better solution based on IoC framework like Spring, Picocontainer or JBoss Microcontainer.
 * 
 * @author <a href="mailto:mposolda@gmail.com">Marek Posolda</a>
 * @version $Revision$
 */
public class ServiceFactory
{
   // singleton instance
   private static ServiceFactory instance = null;
   
   // Application classes
   private ObjectContextBuilder objectContextBuilder;
   private DomainMetadataBuilder domainMetadataBuilder;
   private DomainMetadata domainMetadata;
   private Converter converter;
   private ConverterProvider converterProvider;
   

   // Empty constructor. All components are initialized during call to init() method.
   private ServiceFactory()
   {      
   }
   
   /**
    * 
    * @return singleton instance of ServiceFactory
    */
   public static ServiceFactory getInstance()
   {
      if (instance == null)
      {
         synchronized (ServiceFactory.class)
         {
            if (instance == null)
            {
               instance = new ServiceFactory();
               instance.init();
            }
         }
      }
      return instance;
   }
   
   /**
    * Initialize all application components. We need to ensure correct order because of some dependencies between components.
    *
    */
   private void init()
   {
      try
      {
         converter = new ConverterImpl();
         converterProvider = new ConverterProviderImpl();         
         objectContextBuilder = new ObjectContextBuilder();
//         domainMetadataBuilder = new PropertyDomainMetadataBuilderImpl();
         domainMetadataBuilder = new XMLDomainMetadataBuilderImpl();
         domainMetadata = domainMetadataBuilder.build(); // This depends on Converter and ConverterProvider
      }
      catch (Exception e)
      {
         throw new RuntimeException("Exception during initialization of component class.", e);
      }      
   }

   public ObjectContextBuilder getObjectContextBuilder()
   {
      return objectContextBuilder;
   }
   
   public DomainMetadataBuilder getDomainMetadataBuilder()
   {
      return domainMetadataBuilder;
   }       

   public DomainMetadata getDomainMetadata()
   {
      return domainMetadata;
   }    
   
   public Converter getConverter()
   {
      return converter;
   }    
   
   public ConverterProvider getConverterProvider()
   {
      return converterProvider;
   }

   /**
    * Setter method for converterProvider means that user can create his own converterProvider for converting types and 
    * provide it to ServiceFactory at runtime.
    * 
    * @param converterProvider
    */
   public void setConverterProvider(ConverterProvider converterProvider)
   {
      this.converter.resetStringConverterTypes();
      this.converterProvider = converterProvider;
   }        

}

